#pragma once

#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include "../json/json.h" //jsoncpp as the json lib

#define SIMPLE_SERIALIZE(x) v.serialize(#x, x);

class JsonSerializer
{
private:
    bool start(void)
    {
        std::string s = writer_.str();
        int size = s.size();
        if (size > 0)
        {
            if (s.at(size - 1) != '{' && s.at(size - 1) != '[')
            {
                writer_ << ",";
            }
            return false;
        }
        else
            return true;
    }

public:
    JsonSerializer() {}

    template <typename T>
    std::string Serialize(T &value, const char *path, std::ios_base::openmode mode = std::ios_base::openmode::_S_out)
    {
        writer_.clear();
        std::ofstream of;
        of.open(path, mode);
        if (of.is_open())
        {
            std::string s = this->Serialize(value);
            of << s;
            of.close();
            return s;
        }
        else
        {
            std::cout << "can not open file:" << path << std::endl;
        }
        of.close();
        return std::string("");
    }

    template <typename T>
    std::string Serialize(T &value)
    {
        writer_ << "{";
        value.serialize(*this);
        writer_ << "}";
        std::string result = writer_.str();
        return result;
    }

    template <typename T>
    void serialize(const char *name, T &value)
    {
        start();
        writer_ << Json::valueToQuotedString(name) << ":";
        serialize(value);
    }

    template <typename T>
    void serialize(const char *name, std::vector<T> &value)
    {
        start();
        writer_ << Json::valueToQuotedString(name) << ":[";
        for (int i = 0; i < value.size(); ++i)
        {
            serialize(value[i]);
            if (i < (value.size() - 1))
                writer_ << ",";
        }
        writer_ << "]";
    }

    template <typename T>
    void serialize(const char *name, std::vector<T *> &value)
    {
        start();
        writer_ << Json::valueToQuotedString(name) << ":[";
        for (int i = 0; i < value.size(); ++i)
        {
            serialize(*value[i]);
            if (i < (value.size() - 1))
                writer_ << ",";
        }
        writer_ << "]";
    }

    template <typename T>
    void serialize(std::vector<T> &value)
    {
        start();
        // writer_ << Json::valueToQuotedString(name) << ":[";
        writer_ << "[";
        for (int i = 0; i < value.size(); ++i)
        {
            serialize(value[i]);
            if (i < (value.size() - 1))
                writer_ << ",";
        }
        writer_ << "]";
    }

private:
    void serialize(bool &value)
    {
        // writer_.Bool(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(signed char &value)
    {
        // writer_.Int(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(short &value)
    {
        // writer_.Int(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(int &value)
    {
        // writer_.Int(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(long &value)
    {
        // writer_.Int64(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(long long &value)
    {
        // writer_.Int64(value);
        writer_ << Json::valueToString((Json::LargestInt)value);
    }

    void serialize(unsigned char &value)
    {
        // writer_.Uint(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(unsigned short &value)
    {
        // writer_.Uint(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(unsigned int &value)
    {
        // writer_.Uint(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(unsigned long &value)
    {
        // writer_.Uint64(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(unsigned long long &value)
    {
        // writer_.Uint64(value);
        writer_ << Json::valueToString((Json::LargestUInt)value);
    }

    void serialize(float &value)
    {
        // writer_.Double(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(double &value)
    {
        // writer_.Double(value);
        writer_ << Json::valueToString(value);
    }

    void serialize(std::string &value)
    {
        // writer_.String(value.c_str());
        std::string s = Json::valueToQuotedString(value.c_str());
        writer_ << s;
    }
    template <typename T>
    void serialize(T &value)
    {
        // writer_.StartObject();
        writer_ << "{";
        value.serialize(*this);
        // writer_.EndObject();
        writer_ << "}";
    }

public:
    template <typename T>
    void serialize_without_name(T &value)
    {
        start();
        writer_ << "{";
        value.serialize(*this);
        writer_ << "}";
    }

private:
    std::stringstream writer_;
};